#pragma once

#include <linux/tasks.h>
#include <asm/system.h>

#define USER_BASE      0x40000000
#define USER_SIZE      0xC0000000

#define IO_BITMAP_SIZE 32

#include <linux/head.h>
#include <linux/mm.h>
#include <linux/time.h>

#define TASK_RUNNING         0
#define TASK_INTERRUPTIBLE   1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE          3
#define TASK_STOPPED         4
#define TASK_SWAPPING        5

#ifndef NULL
#define NULL ((void *)0)
#endif

#ifdef __KERNEL__

extern void sched_init(void);
extern void trap_init(void);

#endif

struct i387_hard_struct {
    long cwd;
    long swd;
    long twd;
    long fip;
    long fcs;
    long foo;
    long fos;
    long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};

struct tss_struct {
    unsigned short back_link, __blh;
    unsigned long esp0;
    unsigned short ss0, __ss0h;
    unsigned long esp1;
    unsigned short ss1, __ss1h;
    unsigned long esp2;
    unsigned short ss2, __ss2h;
    unsigned long cr3;
    unsigned long eip;
    unsigned long eflags;
    unsigned long eax, ecx, edx, ebx;
    unsigned long esp;
    unsigned long ebp;
    unsigned long esi;
    unsigned long edi;
    unsigned short es, __esh;
    unsigned short cs, __csh;
    unsigned short ss, __ssh;
    unsigned short ds, __dsh;
    unsigned short fs, __fsh;
    unsigned short gs, __gsh;
    unsigned short ldt, __ldth;
    unsigned short trace, bitmap;
    unsigned long off, tr;
    unsigned long cr2, trap_no, error_code;
    struct i387_hard_struct i387;
};

struct task_struct {
    volatile long state;
    struct task_struct *next_task, *prev_task;
    unsigned long kernel_stack_page;
    unsigned long start_code;
    int pid, pgrp, session;
    struct desc_struct ldt[3];
    struct tss_struct tss;
};

#define INIT_TASK \
    { \
        0, &init_task, &init_task, (unsigned long)&init_kernel_stack, 0, 0, 0, 0, \
            /*ldt*/ {{0, 0}, {0xffff, 0xcffa00}, {0xffff, 0xcff200}}, /*tss*/ { \
            0, 0, \
                sizeof(init_kernel_stack) + (long)&init_kernel_stack, KERNEL_DS, 0, \
                0, 0, 0, 0, 0, 0, \
                (long)&swapper_pg_dir, \
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
                USER_DS, 0, USER_DS, 0, USER_DS, 0, USER_DS, 0, USER_DS, 0, USER_DS, 0, \
                _LDT(0), 0, \
                0, 0x8000, \
                0, _TSS(0), 0, 0, 0, /* 387 state */ {} \
        } \
    }

extern struct task_struct init_task;
extern struct task_struct *task[NR_TASKS];
extern struct task_struct *current;

#define FIRST_TSS_ENTRY 8
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY + 1)
#define _TSS(n)         ((((unsigned long)n) << 4) + (FIRST_TSS_ENTRY << 3))
#define _LDT(n)         ((((unsigned long)n) << 4) + (FIRST_LDT_ENTRY << 3))
#define load_TR(n)      __asm__("ltr %%ax" \
                           : /* no output */ \
                           : "a"(_TSS(n)))
#define load_ldt(n) __asm__("lldt %%ax" \
                            : /* no output */ \
                            : "a"(_LDT(n)))

#define _set_base(addr, base) \
    __asm__("movw %%dx, %0\n\t" \
            "rorl $16, %%edx\n\t" \
            "movb %%dl, %1\n\t" \
            "movb %%dh, %2" \
            : /* no output */ \
            : "m"(*((addr) + 2)), \
              "m"(*((addr) + 4)), \
              "m"(*((addr) + 7)), \
              "d"(base))

#define _set_limit(addr, limit) \
    __asm__("movw %%dx, %0\n\t" \
            "rorl $16, %%edx\n\t" \
            "movb %1, %%dh\n\t" \
            "andb $0xf0, %%dh\n\t" \
            "orb %%dh, %%dl\n\t" \
            "movb %%dl, %1" \
            : /* no output */ \
            : "m"(*(addr)), \
              "m"(*((addr) + 6)), \
              "d"(limit))

#define set_base(ldt, base)   _set_base(((char *)&(ldt)), base)
#define set_limit(ldt, limit) _set_limit(((char *)&(ldt)), (limit - 1) >> 12)

